#ifndef BSP_READER_H_
#define BSP_READER_H_

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <map>

#include "Exception.h"

class Bsp
{
	public:
	typedef enum
	{
		ENTITIES,
		TEXTURES,
		PLANES,
		NODES,
		LEAFS,
		LEAFFACES,
		LEAFBRUSHES,
		MODELS,
		BRUSHES,
		BRUSHSIDES,
		VERTEXES,
		MESHVERTS,
		EFFECTS,
		FACES,
		LIGHTMAPS,
		LIGHTVOLS,
		VISDATA
	} entry_t;

	typedef struct
	{
		int offset;
		int length;
	} direntry_t;

	typedef struct
	{
		char magic[4];
		int version;
		direntry_t direntry[17];
	} header_t;

	typedef struct
	{
		char name[64];
		int flags;
		int contents;
	} texture_t;

	typedef struct
	{
		float mins[3];
		float maxs[3];
		int face;
		int n_faces;
		int brush;
		int n_brushes;
	} model_t;

	typedef struct
	{
		int texture;
		int effect;
		int type;
		int vertex;
		int n_vertexes;
		int meshvert;
		int n_meshverts;
		int lm_index;
		int lm_start[2];
		int lm_size[2];
		float lm_origin[3];
		float lm_vecs[2][3];
		float normal[3];
		int size[2];
	} face_t;

	typedef struct
	{
		float position[3];
		float texcoord[2][2];
		float normal[3];
		unsigned char color[3];
	} vertex_t;

	typedef struct
	{
		int offset;
	} meshvert_t;

	protected:

	header_t header__;
	std::vector<texture_t> textures__;
	std::vector<model_t> models__;
	std::vector<face_t> faces__;
	std::vector<vertex_t> vertexes__;
	std::vector<meshvert_t> meshverts__;

	std::vector<std::map<std::string, std::string> > entities__;

	bool parse_str(std::stringstream& ss, std::string& s);
	std::pair<bool, std::map<std::string, std::string> > parse_acc(std::stringstream& ss);
	void parse_entities(std::stringstream& entities);

	void read_header(std::ifstream& is);
	void read_textures(std::ifstream& is);
	void read_models(std::ifstream& is);
	void read_faces(std::ifstream& is);
	void read_vertexes(std::ifstream& is);
	void read_entities(std::ifstream& is);
	void read_meshverts(std::ifstream& is);

	public:
	Bsp();
	virtual ~Bsp();

	void load(const std::string& map);

	std::vector<std::map<std::string, std::string> >& entities();
	std::vector<texture_t>& textures();
	std::vector<model_t>& models();
	std::vector<face_t>& faces();
	std::vector<vertex_t>& vertexes();
	std::vector<meshvert_t>& meshverts();
};

#endif

